package com.wx.controller;

import com.wx.exception.RequestParamEmptyException;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import java.util.Map;

/**
 * 访问此类中的方法 Controller (Handler)，会执行 CalculateHandlerInvokeTimeInterceptor 拦截器，
 * 计算每个方法的执行时间，然后将计算出的执行时间作为 Model([name,redirect]) 添加到 request 的 attribute 中，
 * 如果是重定向的话，会作为请求参数，添加到 URL 的后边，如: http://localhost:8080/index.jsp？name=redirect
 * @see com.wx.interceptor.CalculateHandlerInvokeTimeInterceptor
 */
@Controller
public class AnnotationController {

	private long lastModified;

	/**
	 * @1: 返回值为 void，用于验证是否通过 RequestToViewNameTranslator 生成了一个 "simple" 的视图名
	 * @2: 验证 Controller (Handler) 执行业务逻辑产生异常时，DispatcherServlet 的处理流程
	 * @3: 在 URL 后边跟上请求参数，验证使用注解 @RequestParam 自动解析请求参数
	 * @测试访问: http://localhost:8080/simple?spendTime=888
	 */
	@RequestMapping(path = "/simple")
	public void simple(@RequestParam(name = "spendTime", required = false) String spendTime) {
		System.out.println("重定向的那个方法 [redirectMethod2] 执行时间: " + spendTime);
//		String[] arr = new String[1];
//		arr[3] = "";
	}

	/**
	 * 假如请求参数比较多，一个一个的写比较麻烦，那么可以使用 Map 自动填充所有的请求参数。
	 * 若 @RequestParam 注解的参数类型是 Map<String, String> 或者 MultiValueMap<String, String>，
	 * 则该 Map 中会 (请求参数比较多的情况下使用)。
	 * @测试访问: http://localhost:8080/simple?spendTime=888&name=Jim
	 */
//	@RequestMapping(path = "/simple")
//	public void simple(@RequestParam(required = false) Map<String, String> map) {
//		map.forEach((key, value) -> {
//			System.out.println(key + " --> " + value);
//		});
//	}

	/**
	 * 用于验证使用 Last-Modified 处理缓存
	 */
	@RequestMapping(path = "/lastModified")
	public String lastModified(WebRequest request, Model model) {

		if (this.lastModified == 0L) {
			this.lastModified = System.currentTimeMillis();
		}

		if (request.checkNotModified(this.lastModified)) {
			return null;
		}

		model.addAttribute("name", "RequestMapping_LastModified");
		return "simple";
	}

	/**
	 * 用于验证转发的处理流程
	 */
	@RequestMapping(path = "/forward")
	public String forwardMethod(Model model) {
		model.addAttribute("name", "forward");
		return "forward:/WEB-INF/page/simple.jsp";
	}

	/**
	 * 用于验证重定向的处理流程
	 */
	@RequestMapping(path = "/redirect")
	public String redirectMethod(Model model) {
		// TODO: 我们知道重定向是让客户端重新发送一次请求，那么这里的 Model 就不能像转发一样设置到 request 对象中;
		//  而是将 Model 用于 URL 的后面作为请求参数，例如: http://localhost:8080/index.jsp?name=redirect
		//  请求参数的解析在方法参数中使用注解 @RequestParam 进行解析
		model.addAttribute("name", "redirect");
		return "redirect:index.jsp";
	}

	/**
	 * 用于验证重定向的 flash_attribute 的处理流程;
	 * Flash 属性会在重定向前被暂时地保存起来 (通常是保存在 session 中)，重定向后会重新被下一个请求取用并立即从原保存地移除。
	 * {@link #simple(String)} 请求参数使用注解 @RequestParam 进行解析
	 */
	@RequestMapping(path = "/redirect2")
	public String redirectMethod2(RedirectAttributes redirectAttributes) {
		redirectAttributes.addFlashAttribute("name", "Redirect --> flash_attribute");
		return "redirect:/simple";
	}

	/**
	 * 测试自定义异常 {@link RequestParamEmptyException}
	 *  @测试访问: http://localhost:8080/customException
	 */
	@RequestMapping(path = "/customException")
	public String customException(@RequestParam Map<String, String> map, Model model) {
		if (map.size() == 0) {
			throw new RequestParamEmptyException("参数异常");
		} else {
			model.addAttribute("name", "URL带有请求参数");
			return "simple";
		}
	}

	@RequestMapping(path = "/u1")
	public String getPath() {
		return "simple";
	}

	@RequestMapping(path = {"/u1", "/u2"})
	public String getPath2() {
		return "error";
	}
}
